#include "StackupParser.h"

#include "WhereMeasuredParser.h"
#include "IdRefParser.h"
#include "QStringParser.h"
#include "MatDesParser.h"
#include "StackupGroupParser.h"
#include "DoubleParser.h"

#include <QXmlStreamReader>
#include <QString>

namespace Ipc2581b
{

StackupParser::StackupParser(
    QStringParser *&_nameParser
    , DoubleParser *&_overallThicknessParser
    , DoubleParser *&_tolPlusParser
    , DoubleParser *&_tolMinusParser
    , WhereMeasuredParser *&_whereMeasuredParser
    , QStringParser *&_commentParser
    , MatDesParser *&_matDesParser
    , IdRefParser *&_specRefParser
    , StackupGroupParser *&_stackupGroupParser
):    m_nameParser(_nameParser)
    , m_overallThicknessParser(_overallThicknessParser)
    , m_tolPlusParser(_tolPlusParser)
    , m_tolMinusParser(_tolMinusParser)
    , m_whereMeasuredParser(_whereMeasuredParser)
    , m_commentParser(_commentParser)
    , m_matDesParser(_matDesParser)
    , m_specRefParser(_specRefParser)
    , m_stackupGroupParser(_stackupGroupParser)
{

}

bool StackupParser::parse(QXmlStreamReader *reader)
{
    /* Pre */

    m_result.reset(new Stackup());

    /* Attributes */

    QStringRef data;
    if (reader->attributes().hasAttribute(QStringLiteral("name")))
    {
        data = reader->attributes().value(QStringLiteral("name"));
        if (!m_nameParser->parse(reader, data))
            return false;
        m_result->nameOptional = Optional<QString>(m_nameParser->result());
    }
    if (reader->attributes().hasAttribute(QStringLiteral("overallThickness")))
    {
        data = reader->attributes().value(QStringLiteral("overallThickness"));
        if (!m_overallThicknessParser->parse(reader, data))
            return false;
        m_result->overallThickness = m_overallThicknessParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("overallThickness: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("tolPlus")))
    {
        data = reader->attributes().value(QStringLiteral("tolPlus"));
        if (!m_tolPlusParser->parse(reader, data))
            return false;
        m_result->tolPlus = m_tolPlusParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("tolPlus: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("tolMinus")))
    {
        data = reader->attributes().value(QStringLiteral("tolMinus"));
        if (!m_tolMinusParser->parse(reader, data))
            return false;
        m_result->tolMinus = m_tolMinusParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("tolMinus: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("whereMeasured")))
    {
        data = reader->attributes().value(QStringLiteral("whereMeasured"));
        if (!m_whereMeasuredParser->parse(reader, data))
            return false;
        m_result->whereMeasured = m_whereMeasuredParser->result();
    }
    else
    {
        reader->raiseError(QStringLiteral("whereMeasured: Attribute is required"));
        return false;
    }
    if (reader->attributes().hasAttribute(QStringLiteral("comment")))
    {
        data = reader->attributes().value(QStringLiteral("comment"));
        if (!m_commentParser->parse(reader, data))
            return false;
        m_result->commentOptional = Optional<QString>(m_commentParser->result());
    }

    /* Elements */

    while (reader->readNextStartElement())
    {
        auto name = reader->name();
        if (name == QStringLiteral("MatDes"))
        {
            if (!m_matDesParser->parse(reader))
                return false;
            auto result = m_matDesParser->result();
            m_result->matDesOptional = Optional<MatDes*>(result);
        }
        else if (name == QStringLiteral("SpecRef"))
        {
            if (!m_specRefParser->parse(reader))
                return false;
            auto result = m_specRefParser->result();
            m_result->specRefList.append(result);
        }
        else if (name == QStringLiteral("StackupGroup"))
        {
            if (!m_stackupGroupParser->parse(reader))
                return false;
            auto result = m_stackupGroupParser->result();
            m_result->stackupGroupList.append(result);
        }
        else
            reader->skipCurrentElement();
    }

    /* Post */

    // TODO: Check multiplicity of elements/attributes

    return true;
}

Stackup *StackupParser::result()
{
    return m_result.take();
}

}